home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / perl5 / 5.8.7 / Unicode / UCD.pm < prev   
Text File  |  2006-04-25  |  23KB  |  821 lines

  1. package Unicode::UCD;
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. our $VERSION = '0.23';
  7.  
  8. use Storable qw(dclone);
  9.  
  10. require Exporter;
  11.  
  12. our @ISA = qw(Exporter);
  13.  
  14. our @EXPORT_OK = qw(charinfo
  15.             charblock charscript
  16.             charblocks charscripts
  17.             charinrange
  18.             compexcl
  19.             casefold casespec
  20.             namedseq);
  21.  
  22. use Carp;
  23.  
  24. =head1 NAME
  25.  
  26. Unicode::UCD - Unicode character database
  27.  
  28. =head1 SYNOPSIS
  29.  
  30.     use Unicode::UCD 'charinfo';
  31.     my $charinfo   = charinfo($codepoint);
  32.  
  33.     use Unicode::UCD 'charblock';
  34.     my $charblock  = charblock($codepoint);
  35.  
  36.     use Unicode::UCD 'charscript';
  37.     my $charscript = charscript($codepoint);
  38.  
  39.     use Unicode::UCD 'charblocks';
  40.     my $charblocks = charblocks();
  41.  
  42.     use Unicode::UCD 'charscripts';
  43.     my %charscripts = charscripts();
  44.  
  45.     use Unicode::UCD qw(charscript charinrange);
  46.     my $range = charscript($script);
  47.     print "looks like $script\n" if charinrange($range, $codepoint);
  48.  
  49.     use Unicode::UCD 'compexcl';
  50.     my $compexcl = compexcl($codepoint);
  51.  
  52.     use Unicode::UCD 'namedseq';
  53.     my $namedseq = namedseq($named_sequence_name);
  54.  
  55.     my $unicode_version = Unicode::UCD::UnicodeVersion();
  56.  
  57. =head1 DESCRIPTION
  58.  
  59. The Unicode::UCD module offers a simple interface to the Unicode
  60. Character Database.
  61.  
  62. =cut
  63.  
  64. my $UNICODEFH;
  65. my $BLOCKSFH;
  66. my $SCRIPTSFH;
  67. my $VERSIONFH;
  68. my $COMPEXCLFH;
  69. my $CASEFOLDFH;
  70. my $CASESPECFH;
  71. my $NAMEDSEQFH;
  72.  
  73. sub openunicode {
  74.     my ($rfh, @path) = @_;
  75.     my $f;
  76.     unless (defined $$rfh) {
  77.     for my $d (@INC) {
  78.         use File::Spec;
  79.         $f = File::Spec->catfile($d, "unicore", @path);
  80.         last if open($$rfh, $f);
  81.         undef $f;
  82.     }
  83.     croak __PACKAGE__, ": failed to find ",
  84.               File::Spec->catfile(@path), " in @INC"
  85.         unless defined $f;
  86.     }
  87.     return $f;
  88. }
  89.  
  90. =head2 charinfo
  91.  
  92.     use Unicode::UCD 'charinfo';
  93.  
  94.     my $charinfo = charinfo(0x41);
  95.  
  96. charinfo() returns a reference to a hash that has the following fields
  97. as defined by the Unicode standard:
  98.  
  99.     key
  100.  
  101.     code             code point with at least four hexdigits
  102.     name             name of the character IN UPPER CASE
  103.     category         general category of the character
  104.     combining        classes used in the Canonical Ordering Algorithm
  105.     bidi             bidirectional category
  106.     decomposition    character decomposition mapping
  107.     decimal          if decimal digit this is the integer numeric value
  108.     digit            if digit this is the numeric value
  109.     numeric          if numeric is the integer or rational numeric value
  110.     mirrored         if mirrored in bidirectional text
  111.     unicode10        Unicode 1.0 name if existed and different
  112.     comment          ISO 10646 comment field
  113.     upper            uppercase equivalent mapping
  114.     lower            lowercase equivalent mapping
  115.     title            titlecase equivalent mapping
  116.  
  117.     block            block the character belongs to (used in \p{In...})
  118.     script           script the character belongs to
  119.  
  120. If no match is found, a reference to an empty hash is returned.
  121.  
  122. The C<block> property is the same as returned by charinfo().  It is
  123. not defined in the Unicode Character Database proper (Chapter 4 of the
  124. Unicode 3.0 Standard, aka TUS3) but instead in an auxiliary database
  125. (Chapter 14 of TUS3).  Similarly for the C<script> property.
  126.  
  127. Note that you cannot do (de)composition and casing based solely on the
  128. above C<decomposition> and C<lower>, C<upper>, C<title>, properties,
  129. you will need also the compexcl(), casefold(), and casespec() functions.
  130.  
  131. =cut
  132.  
  133. # NB: This function is duplicated in charnames.pm
  134. sub _getcode {
  135.     my $arg = shift;
  136.  
  137.     if ($arg =~ /^[1-9]\d*$/) {
  138.     return $arg;
  139.     } elsif ($arg =~ /^(?:[Uu]\+|0[xX])?([[:xdigit:]]+)$/) {
  140.     return hex($1);
  141.     }
  142.  
  143.     return;
  144. }
  145.  
  146. # Lingua::KO::Hangul::Util not part of the standard distribution
  147. # but it will be used if available.
  148.  
  149. eval { require Lingua::KO::Hangul::Util };
  150. my $hasHangulUtil = ! $@;
  151. if ($hasHangulUtil) {
  152.     Lingua::KO::Hangul::Util->import();
  153. }
  154.  
  155. sub hangul_decomp { # internal: called from charinfo
  156.     if ($hasHangulUtil) {
  157.     my @tmp = decomposeHangul(shift);
  158.     return sprintf("%04X %04X",      @tmp) if @tmp == 2;
  159.     return sprintf("%04X %04X %04X", @tmp) if @tmp == 3;
  160.     }
  161.     return;
  162. }
  163.  
  164. sub hangul_charname { # internal: called from charinfo
  165.     return sprintf("HANGUL SYLLABLE-%04X", shift);
  166. }
  167.  
  168. sub han_charname { # internal: called from charinfo
  169.     return sprintf("CJK UNIFIED IDEOGRAPH-%04X", shift);
  170. }
  171.  
  172. my @CharinfoRanges = (
  173. # block name
  174. # [ first, last, coderef to name, coderef to decompose ],
  175. # CJK Ideographs Extension A
  176.   [ 0x3400,   0x4DB5,   \&han_charname,   undef  ],
  177. # CJK Ideographs
  178.   [ 0x4E00,   0x9FA5,   \&han_charname,   undef  ],
  179. # Hangul Syllables
  180.   [ 0xAC00,   0xD7A3,   $hasHangulUtil ? \&getHangulName : \&hangul_charname,  \&hangul_decomp ],
  181. # Non-Private Use High Surrogates
  182.   [ 0xD800,   0xDB7F,   undef,   undef  ],
  183. # Private Use High Surrogates
  184.   [ 0xDB80,   0xDBFF,   undef,   undef  ],
  185. # Low Surrogates
  186.   [ 0xDC00,   0xDFFF,   undef,   undef  ],
  187. # The Private Use Area
  188.   [ 0xE000,   0xF8FF,   undef,   undef  ],
  189. # CJK Ideographs Extension B
  190.   [ 0x20000,  0x2A6D6,  \&han_charname,   undef  ],
  191. # Plane 15 Private Use Area
  192.   [ 0xF0000,  0xFFFFD,  undef,   undef  ],
  193. # Plane 16 Private Use Area
  194.   [ 0x100000, 0x10FFFD, undef,   undef  ],
  195. );
  196.  
  197. sub charinfo {
  198.     my $arg  = shift;
  199.     my $code = _getcode($arg);
  200.     croak __PACKAGE__, "::charinfo: unknown code '$arg'"
  201.     unless defined $code;
  202.     my $hexk = sprintf("%06X", $code);
  203.     my($rcode,$rname,$rdec);
  204.     foreach my $range (@CharinfoRanges){
  205.       if ($range->[0] <= $code && $code <= $range->[1]) {
  206.         $rcode = $hexk;
  207.     $rcode =~ s/^0+//;
  208.     $rcode =  sprintf("%04X", hex($rcode));
  209.         $rname = $range->[2] ? $range->[2]->($code) : '';
  210.         $rdec  = $range->[3] ? $range->[3]->($code) : '';
  211.         $hexk  = sprintf("%06X", $range->[0]); # replace by the first
  212.         last;
  213.       }
  214.     }
  215.     openunicode(\$UNICODEFH, "UnicodeData.txt");
  216.     if (defined $UNICODEFH) {
  217.     use Search::Dict 1.02;
  218.     if (look($UNICODEFH, "$hexk;", { xfrm => sub { $_[0] =~ /^([^;]+);(.+)/; sprintf "%06X;$2", hex($1) } } ) >= 0) {
  219.         my $line = <$UNICODEFH>;
  220.         return unless defined $line;
  221.         chomp $line;
  222.         my %prop;
  223.         @prop{qw(
  224.              code name category
  225.              combining bidi decomposition
  226.              decimal digit numeric
  227.              mirrored unicode10 comment
  228.              upper lower title
  229.             )} = split(/;/, $line, -1);
  230.         $hexk =~ s/^0+//;
  231.         $hexk =  sprintf("%04X", hex($hexk));
  232.         if ($prop{code} eq $hexk) {
  233.         $prop{block}  = charblock($code);
  234.         $prop{script} = charscript($code);
  235.         if(defined $rname){
  236.                     $prop{code} = $rcode;
  237.                     $prop{name} = $rname;
  238.                     $prop{decomposition} = $rdec;
  239.                 }
  240.         return \%prop;
  241.         }
  242.     }
  243.     }
  244.     return;
  245. }
  246.  
  247. sub _search { # Binary search in a [[lo,hi,prop],[...],...] table.
  248.     my ($table, $lo, $hi, $code) = @_;
  249.  
  250.     return if $lo > $hi;
  251.  
  252.     my $mid = int(($lo+$hi) / 2);
  253.  
  254.     if ($table->[$mid]->[0] < $code) {
  255.     if ($table->[$mid]->[1] >= $code) {
  256.         return $table->[$mid]->[2];
  257.     } else {
  258.         _search($table, $mid + 1, $hi, $code);
  259.     }
  260.     } elsif ($table->[$mid]->[0] > $code) {
  261.     _search($table, $lo, $mid - 1, $code);
  262.     } else {
  263.     return $table->[$mid]->[2];
  264.     }
  265. }
  266.  
  267. sub charinrange {
  268.     my ($range, $arg) = @_;
  269.     my $code = _getcode($arg);
  270.     croak __PACKAGE__, "::charinrange: unknown code '$arg'"
  271.     unless defined $code;
  272.     _search($range, 0, $#$range, $code);
  273. }
  274.  
  275. =head2 charblock
  276.  
  277.     use Unicode::UCD 'charblock';
  278.  
  279.     my $charblock = charblock(0x41);
  280.     my $charblock = charblock(1234);
  281.     my $charblock = charblock("0x263a");
  282.     my $charblock = charblock("U+263a");
  283.  
  284.     my $range     = charblock('Armenian');
  285.  
  286. With a B<code point argument> charblock() returns the I<block> the character
  287. belongs to, e.g.  C<Basic Latin>.  Note that not all the character
  288. positions within all blocks are defined.
  289.  
  290. See also L</Blocks versus Scripts>.
  291.  
  292. If supplied with an argument that can't be a code point, charblock() tries
  293. to do the opposite and interpret the argument as a character block. The
  294. return value is a I<range>: an anonymous list of lists that contain
  295. I<start-of-range>, I<end-of-range> code point pairs. You can test whether
  296. a code point is in a range using the L</charinrange> function. If the
  297. argument is not a known charater block, C<undef> is returned.
  298.  
  299. =cut
  300.  
  301. my @BLOCKS;
  302. my %BLOCKS;
  303.  
  304. sub _charblocks {
  305.     unless (@BLOCKS) {
  306.     if (openunicode(\$BLOCKSFH, "Blocks.txt")) {
  307.         local $_;
  308.         while (<$BLOCKSFH>) {
  309.         if (/^([0-9A-F]+)\.\.([0-9A-F]+);\s+(.+)/) {
  310.             my ($lo, $hi) = (hex($1), hex($2));
  311.             my $subrange = [ $lo, $hi, $3 ];
  312.             push @BLOCKS, $subrange;
  313.             push @{$BLOCKS{$3}}, $subrange;
  314.         }
  315.         }
  316.         close($BLOCKSFH);
  317.     }
  318.     }
  319. }
  320.  
  321. sub charblock {
  322.     my $arg = shift;
  323.  
  324.     _charblocks() unless @BLOCKS;
  325.  
  326.     my $code = _getcode($arg);
  327.  
  328.     if (defined $code) {
  329.     _search(\@BLOCKS, 0, $#BLOCKS, $code);
  330.     } else {
  331.     if (exists $BLOCKS{$arg}) {
  332.         return dclone $BLOCKS{$arg};
  333.     } else {
  334.         return;
  335.     }
  336.     }
  337. }
  338.  
  339. =head2 charscript
  340.  
  341.     use Unicode::UCD 'charscript';
  342.  
  343.     my $charscript = charscript(0x41);
  344.     my $charscript = charscript(1234);
  345.     my $charscript = charscript("U+263a");
  346.  
  347.     my $range      = charscript('Thai');
  348.  
  349. With a B<code point argument> charscript() returns the I<script> the
  350. character belongs to, e.g.  C<Latin>, C<Greek>, C<Han>.
  351.  
  352. See also L</Blocks versus Scripts>.
  353.  
  354. If supplied with an argument that can't be a code point, charscript() tries
  355. to do the opposite and interpret the argument as a character script. The
  356. return value is a I<range>: an anonymous list of lists that contain
  357. I<start-of-range>, I<end-of-range> code point pairs. You can test whether a
  358. code point is in a range using the L</charinrange> function. If the
  359. argument is not a known charater script, C<undef> is returned.
  360.  
  361. =cut
  362.  
  363. my @SCRIPTS;
  364. my %SCRIPTS;
  365.  
  366. sub _charscripts {
  367.     unless (@SCRIPTS) {
  368.     if (openunicode(\$SCRIPTSFH, "Scripts.txt")) {
  369.         local $_;
  370.         while (<$SCRIPTSFH>) {
  371.         if (/^([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+)/) {
  372.             my ($lo, $hi) = (hex($1), $2 ? hex($2) : hex($1));
  373.             my $script = lc($3);
  374.             $script =~ s/\b(\w)/uc($1)/ge;
  375.             my $subrange = [ $lo, $hi, $script ];
  376.             push @SCRIPTS, $subrange;
  377.             push @{$SCRIPTS{$script}}, $subrange;
  378.         }
  379.         }
  380.         close($SCRIPTSFH);
  381.         @SCRIPTS = sort { $a->[0] <=> $b->[0] } @SCRIPTS;
  382.     }
  383.     }
  384. }
  385.  
  386. sub charscript {
  387.     my $arg = shift;
  388.  
  389.     _charscripts() unless @SCRIPTS;
  390.  
  391.     my $code = _getcode($arg);
  392.  
  393.     if (defined $code) {
  394.     _search(\@SCRIPTS, 0, $#SCRIPTS, $code);
  395.     } else {
  396.     if (exists $SCRIPTS{$arg}) {
  397.         return dclone $SCRIPTS{$arg};
  398.     } else {
  399.         return;
  400.     }
  401.     }
  402. }
  403.  
  404. =head2 charblocks
  405.  
  406.     use Unicode::UCD 'charblocks';
  407.  
  408.     my $charblocks = charblocks();
  409.  
  410. charblocks() returns a reference to a hash with the known block names
  411. as the keys, and the code point ranges (see L</charblock>) as the values.
  412.  
  413. See also L</Blocks versus Scripts>.
  414.  
  415. =cut
  416.  
  417. sub charblocks {
  418.     _charblocks() unless %BLOCKS;
  419.     return dclone \%BLOCKS;
  420. }
  421.  
  422. =head2 charscripts
  423.  
  424.     use Unicode::UCD 'charscripts';
  425.  
  426.     my %charscripts = charscripts();
  427.  
  428. charscripts() returns a hash with the known script names as the keys,
  429. and the code point ranges (see L</charscript>) as the values.
  430.  
  431. See also L</Blocks versus Scripts>.
  432.  
  433. =cut
  434.  
  435. sub charscripts {
  436.     _charscripts() unless %SCRIPTS;
  437.     return dclone \%SCRIPTS;
  438. }
  439.  
  440. =head2 Blocks versus Scripts
  441.  
  442. The difference between a block and a script is that scripts are closer
  443. to the linguistic notion of a set of characters required to present
  444. languages, while block is more of an artifact of the Unicode character
  445. numbering and separation into blocks of (mostly) 256 characters.
  446.  
  447. For example the Latin B<script> is spread over several B<blocks>, such
  448. as C<Basic Latin>, C<Latin 1 Supplement>, C<Latin Extended-A>, and
  449. C<Latin Extended-B>.  On the other hand, the Latin script does not
  450. contain all the characters of the C<Basic Latin> block (also known as
  451. the ASCII): it includes only the letters, and not, for example, the digits
  452. or the punctuation.
  453.  
  454. For blocks see http://www.unicode.org/Public/UNIDATA/Blocks.txt
  455.  
  456. For scripts see UTR #24: http://www.unicode.org/unicode/reports/tr24/
  457.  
  458. =head2 Matching Scripts and Blocks
  459.  
  460. Scripts are matched with the regular-expression construct
  461. C<\p{...}> (e.g. C<\p{Tibetan}> matches characters of the Tibetan script),
  462. while C<\p{In...}> is used for blocks (e.g. C<\p{InTibetan}> matches
  463. any of the 256 code points in the Tibetan block).
  464.  
  465. =head2 Code Point Arguments
  466.  
  467. A I<code point argument> is either a decimal or a hexadecimal scalar
  468. designating a Unicode character, or C<U+> followed by hexadecimals
  469. designating a Unicode character.  In other words, if you want a code
  470. point to be interpreted as a hexadecimal number, you must prefix it
  471. with either C<0x> or C<U+>, because a string like e.g. C<123> will
  472. be interpreted as a decimal code point.  Also note that Unicode is
  473. B<not> limited to 16 bits (the number of Unicode characters is
  474. open-ended, in theory unlimited): you may have more than 4 hexdigits.
  475.  
  476. =head2 charinrange
  477.  
  478. In addition to using the C<\p{In...}> and C<\P{In...}> constructs, you
  479. can also test whether a code point is in the I<range> as returned by
  480. L</charblock> and L</charscript> or as the values of the hash returned
  481. by L</charblocks> and L</charscripts> by using charinrange():
  482.  
  483.     use Unicode::UCD qw(charscript charinrange);
  484.  
  485.     $range = charscript('Hiragana');
  486.     print "looks like hiragana\n" if charinrange($range, $codepoint);
  487.  
  488. =cut
  489.  
  490. =head2 compexcl
  491.  
  492.     use Unicode::UCD 'compexcl';
  493.  
  494.     my $compexcl = compexcl("09dc");
  495.  
  496. The compexcl() returns the composition exclusion (that is, if the
  497. character should not be produced during a precomposition) of the 
  498. character specified by a B<code point argument>.
  499.  
  500. If there is a composition exclusion for the character, true is
  501. returned.  Otherwise, false is returned.
  502.  
  503. =cut
  504.  
  505. my %COMPEXCL;
  506.  
  507. sub _compexcl {
  508.     unless (%COMPEXCL) {
  509.     if (openunicode(\$COMPEXCLFH, "CompositionExclusions.txt")) {
  510.         local $_;
  511.         while (<$COMPEXCLFH>) {
  512.         if (/^([0-9A-F]+)\s+\#\s+/) {
  513.             my $code = hex($1);
  514.             $COMPEXCL{$code} = undef;
  515.         }
  516.         }
  517.         close($COMPEXCLFH);
  518.     }
  519.     }
  520. }
  521.  
  522. sub compexcl {
  523.     my $arg  = shift;
  524.     my $code = _getcode($arg);
  525.     croak __PACKAGE__, "::compexcl: unknown code '$arg'"
  526.     unless defined $code;
  527.  
  528.     _compexcl() unless %COMPEXCL;
  529.  
  530.     return exists $COMPEXCL{$code};
  531. }
  532.  
  533. =head2 casefold
  534.  
  535.     use Unicode::UCD 'casefold';
  536.  
  537.     my $casefold = casefold("00DF");
  538.  
  539. The casefold() returns the locale-independent case folding of the
  540. character specified by a B<code point argument>.
  541.  
  542. If there is a case folding for that character, a reference to a hash
  543. with the following fields is returned:
  544.  
  545.     key
  546.  
  547.     code             code point with at least four hexdigits
  548.     status           "C", "F", "S", or "I"
  549.     mapping          one or more codes separated by spaces
  550.  
  551. The meaning of the I<status> is as follows:
  552.  
  553.    C                 common case folding, common mappings shared
  554.                      by both simple and full mappings
  555.    F                 full case folding, mappings that cause strings
  556.                      to grow in length. Multiple characters are separated
  557.                      by spaces
  558.    S                 simple case folding, mappings to single characters
  559.                      where different from F
  560.    I                 special case for dotted uppercase I and
  561.                      dotless lowercase i
  562.                      - If this mapping is included, the result is
  563.                        case-insensitive, but dotless and dotted I's
  564.                        are not distinguished
  565.                      - If this mapping is excluded, the result is not
  566.                        fully case-insensitive, but dotless and dotted
  567.                        I's are distinguished
  568.  
  569. If there is no case folding for that character, C<undef> is returned.
  570.  
  571. For more information about case mappings see
  572. http://www.unicode.org/unicode/reports/tr21/
  573.  
  574. =cut
  575.  
  576. my %CASEFOLD;
  577.  
  578. sub _casefold {
  579.     unless (%CASEFOLD) {
  580.     if (openunicode(\$CASEFOLDFH, "CaseFolding.txt")) {
  581.         local $_;
  582.         while (<$CASEFOLDFH>) {
  583.         if (/^([0-9A-F]+); ([CFSI]); ([0-9A-F]+(?: [0-9A-F]+)*);/) {
  584.             my $code = hex($1);
  585.             $CASEFOLD{$code} = { code    => $1,
  586.                      status  => $2,
  587.                      mapping => $3 };
  588.         }
  589.         }
  590.         close($CASEFOLDFH);
  591.     }
  592.     }
  593. }
  594.  
  595. sub casefold {
  596.     my $arg  = shift;
  597.     my $code = _getcode($arg);
  598.     croak __PACKAGE__, "::casefold: unknown code '$arg'"
  599.     unless defined $code;
  600.  
  601.     _casefold() unless %CASEFOLD;
  602.  
  603.     return $CASEFOLD{$code};
  604. }
  605.  
  606. =head2 casespec
  607.  
  608.     use Unicode::UCD 'casespec';
  609.  
  610.     my $casespec = casespec("FB00");
  611.  
  612. The casespec() returns the potentially locale-dependent case mapping
  613. of the character specified by a B<code point argument>.  The mapping
  614. may change the length of the string (which the basic Unicode case
  615. mappings as returned by charinfo() never do).
  616.  
  617. If there is a case folding for that character, a reference to a hash
  618. with the following fields is returned:
  619.  
  620.     key
  621.  
  622.     code             code point with at least four hexdigits
  623.     lower            lowercase
  624.     title            titlecase
  625.     upper            uppercase
  626.     condition        condition list (may be undef)
  627.  
  628. The C<condition> is optional.  Where present, it consists of one or
  629. more I<locales> or I<contexts>, separated by spaces (other than as
  630. used to separate elements, spaces are to be ignored).  A condition
  631. list overrides the normal behavior if all of the listed conditions are
  632. true.  Case distinctions in the condition list are not significant.
  633. Conditions preceded by "NON_" represent the negation of the condition.
  634.  
  635. Note that when there are multiple case folding definitions for a
  636. single code point because of different locales, the value returned by
  637. casespec() is a hash reference which has the locales as the keys and
  638. hash references as described above as the values.
  639.  
  640. A I<locale> is defined as a 2-letter ISO 3166 country code, possibly
  641. followed by a "_" and a 2-letter ISO language code (possibly followed
  642. by a "_" and a variant code).  You can find the lists of those codes,
  643. see L<Locale::Country> and L<Locale::Language>.
  644.  
  645. A I<context> is one of the following choices:
  646.  
  647.     FINAL            The letter is not followed by a letter of
  648.                      general category L (e.g. Ll, Lt, Lu, Lm, or Lo)
  649.     MODERN           The mapping is only used for modern text
  650.     AFTER_i          The last base character was "i" (U+0069)
  651.  
  652. For more information about case mappings see
  653. http://www.unicode.org/unicode/reports/tr21/
  654.  
  655. =cut
  656.  
  657. my %CASESPEC;
  658.  
  659. sub _casespec {
  660.     unless (%CASESPEC) {
  661.     if (openunicode(\$CASESPECFH, "SpecialCasing.txt")) {
  662.         local $_;
  663.         while (<$CASESPECFH>) {
  664.         if (/^([0-9A-F]+); ([0-9A-F]+(?: [0-9A-F]+)*)?; ([0-9A-F]+(?: [0-9A-F]+)*)?; ([0-9A-F]+(?: [0-9A-F]+)*)?; (\w+(?: \w+)*)?/) {
  665.             my ($hexcode, $lower, $title, $upper, $condition) =
  666.             ($1, $2, $3, $4, $5);
  667.             my $code = hex($hexcode);
  668.             if (exists $CASESPEC{$code}) {
  669.             if (exists $CASESPEC{$code}->{code}) {
  670.                 my ($oldlower,
  671.                 $oldtitle,
  672.                 $oldupper,
  673.                 $oldcondition) =
  674.                     @{$CASESPEC{$code}}{qw(lower
  675.                                title
  676.                                upper
  677.                                condition)};
  678.                 if (defined $oldcondition) {
  679.                 my ($oldlocale) =
  680.                 ($oldcondition =~ /^([a-z][a-z](?:_\S+)?)/);
  681.                 delete $CASESPEC{$code};
  682.                 $CASESPEC{$code}->{$oldlocale} =
  683.                 { code      => $hexcode,
  684.                   lower     => $oldlower,
  685.                   title     => $oldtitle,
  686.                   upper     => $oldupper,
  687.                   condition => $oldcondition };
  688.                 }
  689.             }
  690.             my ($locale) =
  691.                 ($condition =~ /^([a-z][a-z](?:_\S+)?)/);
  692.             $CASESPEC{$code}->{$locale} =
  693.             { code      => $hexcode,
  694.               lower     => $lower,
  695.               title     => $title,
  696.               upper     => $upper,
  697.               condition => $condition };
  698.             } else {
  699.             $CASESPEC{$code} =
  700.             { code      => $hexcode,
  701.               lower     => $lower,
  702.               title     => $title,
  703.               upper     => $upper,
  704.               condition => $condition };
  705.             }
  706.         }
  707.         }
  708.         close($CASESPECFH);
  709.     }
  710.     }
  711. }
  712.  
  713. sub casespec {
  714.     my $arg  = shift;
  715.     my $code = _getcode($arg);
  716.     croak __PACKAGE__, "::casespec: unknown code '$arg'"
  717.     unless defined $code;
  718.  
  719.     _casespec() unless %CASESPEC;
  720.  
  721.     return ref $CASESPEC{$code} ? dclone $CASESPEC{$code} : $CASESPEC{$code};
  722. }
  723.  
  724. =head2 namedseq()
  725.  
  726.     use Unicode::UCD 'namedseq';
  727.  
  728.     my $namedseq = namedseq("KATAKANA LETTER AINU P");
  729.     my @namedseq = namedseq("KATAKANA LETTER AINU P");
  730.     my %namedseq = namedseq();
  731.  
  732. If used with a single argument in a scalar context, returns the string
  733. consisting of the code points of the named sequence, or C<undef> if no
  734. named sequence by that name exists.  If used with a single argument in
  735. a list context, returns list of the code points.  If used with no
  736. arguments in a list context, returns a hash with the names of the
  737. named sequences as the keys and the named sequences as strings as
  738. the values.  Otherwise, returns C<undef> or empty list depending
  739. on the context.
  740.  
  741. (New from Unicode 4.1.0)
  742.  
  743. =cut
  744.  
  745. my %NAMEDSEQ;
  746.  
  747. sub _namedseq {
  748.     unless (%NAMEDSEQ) {
  749.     if (openunicode(\$NAMEDSEQFH, "NamedSequences.txt")) {
  750.         local $_;
  751.         while (<$NAMEDSEQFH>) {
  752.         if (/^(.+)\s*;\s*([0-9A-F]+(?: [0-9A-F]+)*)$/) {
  753.             my ($n, $s) = ($1, $2);
  754.             my @s = map { chr(hex($_)) } split(' ', $s);
  755.             $NAMEDSEQ{$n} = join("", @s);
  756.         }
  757.         }
  758.         close($NAMEDSEQFH);
  759.     }
  760.     }
  761. }
  762.  
  763. sub namedseq {
  764.     _namedseq() unless %NAMEDSEQ;
  765.     my $wantarray = wantarray();
  766.     if (defined $wantarray) {
  767.     if ($wantarray) {
  768.         if (@_ == 0) {
  769.         return %NAMEDSEQ;
  770.         } elsif (@_ == 1) {
  771.         my $s = $NAMEDSEQ{ $_[0] };
  772.         return defined $s ? map { ord($_) } split('', $s) : ();
  773.         }
  774.     } elsif (@_ == 1) {
  775.         return $NAMEDSEQ{ $_[0] };
  776.     }
  777.     }
  778.     return;
  779. }
  780.  
  781. =head2 Unicode::UCD::UnicodeVersion
  782.  
  783. Unicode::UCD::UnicodeVersion() returns the version of the Unicode
  784. Character Database, in other words, the version of the Unicode
  785. standard the database implements.  The version is a string
  786. of numbers delimited by dots (C<'.'>).
  787.  
  788. =cut
  789.  
  790. my $UNICODEVERSION;
  791.  
  792. sub UnicodeVersion {
  793.     unless (defined $UNICODEVERSION) {
  794.     openunicode(\$VERSIONFH, "version");
  795.     chomp($UNICODEVERSION = <$VERSIONFH>);
  796.     close($VERSIONFH);
  797.     croak __PACKAGE__, "::VERSION: strange version '$UNICODEVERSION'"
  798.         unless $UNICODEVERSION =~ /^\d+(?:\.\d+)+$/;
  799.     }
  800.     return $UNICODEVERSION;
  801. }
  802.  
  803. =head2 Implementation Note
  804.  
  805. The first use of charinfo() opens a read-only filehandle to the Unicode
  806. Character Database (the database is included in the Perl distribution).
  807. The filehandle is then kept open for further queries.  In other words,
  808. if you are wondering where one of your filehandles went, that's where.
  809.  
  810. =head1 BUGS
  811.  
  812. Does not yet support EBCDIC platforms.
  813.  
  814. =head1 AUTHOR
  815.  
  816. Jarkko Hietaniemi
  817.  
  818. =cut
  819.  
  820. 1;
  821.